package cn.catsdad.base.repository.impl;

import cn.catsdad.base.entity.BaseEntity;
import cn.catsdad.base.repository.api.IBaseRepository;
import cn.catsdad.constant.iConstant.ICommonWarningType;
import cn.catsdad.util.EnvironmentUtil;
import cn.catsdad.util.StringUtil;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author xuyl
 * @version V1.0.0 2024/7/5
 * @since V100R001
 */
@SuppressWarnings(ICommonWarningType.UNCHECKED)
public class BaseRepositoryImpl<T extends BaseEntity, ID extends Long> extends SimpleJpaRepository<T, ID>
        implements IBaseRepository<T, ID> {

    protected final EntityManager entityManager;
    protected final JpaEntityInformation<T, ID> jpaEntityInformation;

    public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
        this.jpaEntityInformation = (JpaEntityInformation<T, ID>) entityInformation;
    }

    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
        this.jpaEntityInformation = (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager);
    }

    @Override
    @Transactional
    public void batchSave(Collection<T> entities) {
        if (StringUtil.isNotEmpty(entities)) {
            List<T> entityList = new ArrayList<>(entities);
            int batchSize = EnvironmentUtil.getProperty(new EnvironmentUtil.PropertyParam<Integer>().setKey("app.db.batchSize").setDefaultValue(200));
            for (int i = 0; i < entities.size(); i++) {
                T entity = entityList.get(i);
                if (jpaEntityInformation.isNew(entity)) {
                    entityManager.persist(entity);
                } else {
                    entityManager.merge(entity);
                }
                if (i % batchSize == 0) {
                    entityManager.flush();
                    entityManager.clear();
                }
            }
            entityManager.flush();
            entityManager.clear();
        }
    }

    @Override
    @Transactional
    public void batchInsert(Collection<T> entities) {
        if (StringUtil.isNotEmpty(entities)) {
            List<T> entityList = new ArrayList<>(entities);
            int batchSize = EnvironmentUtil.getProperty(new EnvironmentUtil.PropertyParam<Integer>().setKey("app.db.batchSize").setDefaultValue(200));
            for (int i = 0; i < entities.size(); i++) {
                T entity = entityList.get(i);
                entityManager.persist(entity);
                if (i % batchSize == 0) {
                    entityManager.flush();
                    entityManager.clear();
                }
            }
            entityManager.flush();
            entityManager.clear();
        }
    }

    @Override
    @Transactional
    public void batchUpdate(Collection<T> entities) {
        if (StringUtil.isNotEmpty(entities)) {
            List<T> entityList = new ArrayList<>(entities);
            int batchSize = EnvironmentUtil.getProperty(new EnvironmentUtil.PropertyParam<Integer>().setKey("app.db.batchSize").setDefaultValue(200));
            for (int i = 0; i < entities.size(); i++) {
                T entity = entityList.get(i);
                entityManager.merge(entity);
                if (i % batchSize == 0) {
                    entityManager.flush();
                    entityManager.clear();
                }
            }
            entityManager.flush();
            entityManager.clear();
        }
    }


    @Override
    public Class<T> getEntityClass() {
        return jpaEntityInformation.getJavaType();
    }

    @Override
    public String getQueryAlias(){
        return "t";
    }

    @Override
    public JpaEntityInformation<T, ID> getEntityInfo() {
        return this.jpaEntityInformation;
    }
}
